﻿#define USE_SERIALPORT      //使用自定义的串口类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Xml;
using System.Runtime.InteropServices;
using System.Threading;
using Win32;

using HANDLE = System.IntPtr;
using HWND = System.IntPtr;
using System.IO.Ports;
using System.Xml.Linq;
using System.IO;
using System.ComponentModel;
using System.Windows.Threading;
using System.Data;
using System.Windows.Interop;

namespace matrix_screen_pc_prog
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public static System.Globalization.CultureInfo culture_ch = new System.Globalization.CultureInfo("zh-CN");
        public static System.Globalization.CultureInfo culture_en = new System.Globalization.CultureInfo("en-US");
        XmlDocument xDoc = new XmlDocument();
        XmlElement xBaseSetting;
        DataTable pagerDatatable;

        private uint GetXmlAttriValue(XmlElement xml, string attribute, uint def_val)
        {
            uint val = def_val;
            if (xml.GetAttribute(attribute).Length == 0 || !UInt32.TryParse(xml.GetAttribute(attribute), out val))
            {
                xml.SetAttribute(attribute, val.ToString());
            }
            return val;
        }
        private decimal GetXmlAttriValue(XmlElement xml, string attribute, decimal def_val)
        {
            decimal val = def_val;
            if (xBaseSetting.GetAttribute(attribute).Length == 0 || !decimal.TryParse(xml.GetAttribute(attribute), out val))
            {
                xBaseSetting.SetAttribute(attribute, val.ToString());
            }
            return val;
        }

        private bool GetXmlAttriValue(XmlElement xml, string attribute, bool def_val)
        {
            bool val = def_val;
            if (xml.GetAttribute(attribute).Length == 0 || !bool.TryParse(xml.GetAttribute(attribute), out val))
            {
                xml.SetAttribute(attribute, val.ToString());
            }
            return val;
        }

        private bool _createNew;

        public MainWindow()
        {
            string exeName = Properties.Resources.ThreadName;
            Mutex mutex = new Mutex(true, exeName, out _createNew);

            //only one instance is allowed
            if (!_createNew)
            {
                MessageBox.Show(Properties.Resources.ThereAlreadyRun);
                App.Current.Shutdown();
                return;
            }
            pagerDatatable = new DataTable();

            XmlElement xSoundList;


            //FileStream fs = new FileStream("queue_system_setting.dat", FileMode.Open);
            //xmlSetting = XElement.Load(fs, LoadOptions.None);
            //XElement xServiceList = xmlSetting.Element("ServiceList");
            //XElement xBaseSet = xmlSetting.Element("Setting");
            //XElement xSoundList = xmlSetting.Element("SoundList");

            if (System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName == "zh")
            {
                Properties.Resources.Culture = culture_ch;
            }
            else
            {
                Properties.Resources.Culture = culture_en;
            }

            List<ResourceDictionary> dictionaryList = new List<ResourceDictionary>();
            foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
            {
                dictionaryList.Add(dictionary);
            }
            string requestedCulture = string.Format("pack://application:,,,/lang/{0}.xaml", Properties.Resources.Culture.Name);
            ResourceDictionary resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString.Equals(requestedCulture));
            if (resourceDictionary == null)
            {
                requestedCulture = "pack://application:,,,/lang/en-US.xaml";
                resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString.Equals(requestedCulture));
            }
            if (resourceDictionary != null)
            {
                Application.Current.Resources.MergedDictionaries.Remove(resourceDictionary);
                Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
            }
            try
            {
                xDoc.Load("queue_system_setting.dat");
            }
            catch (Exception)
            {
                //MessageBox.Show(this, "Load queue_system_setting.dat failed!");//
                XmlDeclaration xh = xDoc.CreateXmlDeclaration("1.0", "utf-8", null);
                xDoc.AppendChild(xh);
                xDoc.AppendChild(xDoc.CreateElement("MatrixScreen"));
            }
            XmlElement xDocElem = xDoc.DocumentElement;
            XmlNodeList nodes = xDocElem.GetElementsByTagName("BaseSetting");
            if (null == nodes || nodes.Count == 0)
            {
                xBaseSetting = xDoc.CreateElement("BaseSetting");
                xDocElem.AppendChild(xBaseSetting);
            }
            else
            {
                xBaseSetting = (XmlElement)nodes.Item(0);
            }


            nodes = xDocElem.GetElementsByTagName("Services");
            if (nodes.Count == 0)
            {
                xSoundList = xDoc.CreateElement("Services");
                xDocElem.AppendChild(xSoundList);
            }
            else
            {
                xSoundList = (XmlElement)nodes.Item(0);
            }
            while (xSoundList.ChildNodes.Count < 16)
            {
                XmlElement xSound = xDoc.CreateElement("Sound");
                xSound.SetAttribute("Index", xSoundList.ChildNodes.Count.ToString());
                xSound.SetAttribute("Text", (70 + xSoundList.ChildNodes.Count).ToString());
                xSoundList.AppendChild(xSound);
            }
#if USE_SERIALPORT
            port.BaudRate = 9600;
            port.Parity = System.IO.Ports.Parity.None;
            port.StopBits = System.IO.Ports.StopBits.One;
            port.DataBits = 8;
            port.Handshake = Handshake.None;
            port.ReadTimeout = 40;
            port.DataReceived += port_DataReceived;
            if (xBaseSetting.GetAttribute("COM").Length != 0)
                m_port_name = xBaseSetting.GetAttribute("COM");
#else
            comport.BaudRate = 9600;
            comport.ByteSize = 8;
            comport.StopBits = 0;
            comport.DataReceived += DataReceived;
            if (xBaseSetting.GetAttribute("COM").Length != 0)
                m_port_name = xBaseSetting.GetAttribute("COM");
#endif
            m_text_color = GetXmlAttriValue(xBaseSetting, "TextColor", m_text_color);
            m_sound_type = GetXmlAttriValue(xBaseSetting, "SoundType", m_sound_type);
            m_volume = GetXmlAttriValue(xBaseSetting, "Volume", m_volume);
            m_language_id = GetXmlAttriValue(xBaseSetting, "LanguageId", m_language_id);
            m_modulation = GetXmlAttriValue(xBaseSetting, "Modulation", m_modulation);
            m_rf_freq_id = GetXmlAttriValue(xBaseSetting, "RFFreqID", m_rf_freq_id);


            m_temorrow_reset_number = GetXmlAttriValue(xBaseSetting, "TemorrowResetNumber", m_temorrow_reset_number);//
            m_number_format = GetXmlAttriValue(xBaseSetting, "NumberFormat", m_number_format);
            m_power_down_memory = GetXmlAttriValue(xBaseSetting, "PowerDownMemory", m_power_down_memory);// 
            m_push_call_list_front = GetXmlAttriValue(xBaseSetting, "PushCallFront", m_push_call_list_front);
            ports = SerialPort.GetPortNames();

            InitializeComponent();

            txboxNumPrefix.Text = xBaseSetting.GetAttribute("NumPrefix");
            nudRotationTime.Value = GetXmlAttriValue(xBaseSetting, "RotationTime", nudRotationTime.Value);
            nudEliminationTime.Value = GetXmlAttriValue(xBaseSetting, "EliminationTime", nudEliminationTime.Value);
            nudReportTimes.Value = GetXmlAttriValue(xBaseSetting, "ReportTimes", nudReportTimes.Value);
            nudTimeoutTime.Value = GetXmlAttriValue(xBaseSetting, "TimeoutTime", nudTimeoutTime.Value);
            nudStartNum.Value = GetXmlAttriValue(xBaseSetting, "StartNumber", nudStartNum.Value);
            nudEndNum.Value = GetXmlAttriValue(xBaseSetting, "MaxNumber", nudEndNum.Value);

            this.LogoTextBox.Text = xBaseSetting.GetAttribute("logo");
            PagerTypeColumn.ItemsSource = Application.Current.FindResource("keyArrayPagerType") as Pair[];
            PagerStatusColumn.ItemsSource = Application.Current.FindResource("keyArrayItemStatus") as Pair[];
            PagerColorColumn.ItemsSource = Application.Current.FindResource("keyArrayColor") as Pair[];
            //绑定Services类的Color属性   
            //ServColorColumn.SelectedValueBinding = new Binding("Color") { Mode = BindingMode.TwoWay, Converter = new ColorConvertor() };

            m_timer = new DispatcherTimer();
            m_timer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
            m_timer.Tick += TransTimeOut;

            //绑定下第4列语音
            this.PagerServiceColumn.ItemsSource = xSoundList;
            this.PagerServiceColumn.SelectedValuePath = "@Index";
            this.PagerServiceColumn.DisplayMemberPath = "@Text";

            cboRegServiceSound.ItemsSource = xSoundList;
            cboRegServiceSound.SelectedValuePath = "@Index";
            cboRegServiceSound.DisplayMemberPath = "@Text";

            DataColumn[] dc = new DataColumn[]
            {
                new DataColumn("pager_index", typeof(UInt16)),
                new DataColumn("pager_code", typeof(UInt32)),
                new DataColumn("pager_name", typeof(string)),
                new DataColumn("pager_type", typeof(byte)),
                new DataColumn("pager_service", typeof(byte)),
                new DataColumn("pager_color", typeof(byte)),
                new DataColumn("pager_status", typeof(byte))
            };
            pagerDatatable.Columns.AddRange(dc);
            pagerDatatable.TableName = "Pager";

            //DataRow dr = pagerDatatable.NewRow();
            //dr["pager_code"] = string.Format("{0:X8}", 125);
            //dr["pager_name"] = "A001";
            ////dr["pager_id"] = 001;
            //dr["pager_type"] = 1;
            //dt.Rows.Add(dr);
            this.PagerGrid.LoadingRow += PagerGrid_LoadingRow;
            this.PagerGrid.ItemsSource = pagerDatatable.DefaultView;


            //使能Binding
            this.DataContext = this;
        }

        private void PagerGrid_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.Header = e.Row.GetIndex() + 1;    //设置行表头的内容值
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
            source.AddHook(WndProc);
        }

        class dbch_device_type
        {
            public const UInt32 DBT_DEVTYP_OEM = 0x00000000;  // oem-defined device type
            public const UInt32 DBT_DEVTYP_DEVNODE = 0x00000001;  // devnode number
            public const UInt32 DBT_DEVTYP_VOLUME = 0x00000002;  // logical volume
            public const UInt32 DBT_DEVTYP_PORT = 0x00000003;  // serial, parallel
            public const UInt32 DBT_DEVTYP_NET = 0x00000004;  // network resource
        }

        class dbch_device_state
        {
            public const Int32 DBT_DEVICEARRIVAL = 0x8000;
            public const Int32 DBT_DEVICEREMOVECOMPLETE = 0x8004;
        }
        struct DEV_BROADCAST_HDR
        {     /* */
            public UInt32 dbch_size;
            public UInt32 dbch_devicetype;
            public UInt32 dbch_reserved;
        };

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // Handle messages...   
            //#if (WINVER >= 0x0400)
            //#define WM_DEVICECHANGE                 0x0219
            //#endif /* WINVER >= 0x0400 */
            if (msg == 0x0219)
            {
                int wp = wParam.ToInt32();
                if (wp == dbch_device_state.DBT_DEVICEARRIVAL)
                {
                    object phdr = null;
                    phdr = Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_HDR));
                    if (((DEV_BROADCAST_HDR)phdr).dbch_devicetype == dbch_device_type.DBT_DEVTYP_PORT)
                    {
                        string[] port_list = CommPortList;
                        CommPortList = SerialPort.GetPortNames();
                        foreach (string p in CommPortList)
                        {
                            if (!Array.Exists(port_list, element => element.Equals(p)))
                            {
                                PortName = p;
                            }
                        }
                    }
                }
                else if (wp == dbch_device_state.DBT_DEVICEREMOVECOMPLETE)
                {
                    object phdr = null;
                    phdr = Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_HDR));
                    if (((DEV_BROADCAST_HDR)phdr).dbch_devicetype == dbch_device_type.DBT_DEVTYP_PORT)
                    {
                        //string[] port_list = CommPortList;
                        CommPortList = SerialPort.GetPortNames();

                    }
                }

            }
            return IntPtr.Zero;
        }

        delegate void PortCallback(ref byte[] data);

        //private readonly object objlock = new object();
        private byte[] ReadBuffer = new byte[256];
        private int ReadCnt;   //ReadBuffer里已经存着的数据个数

#if USE_SERIALPORT
        void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (port.BytesToRead == 0)
                return;
            //开辟接收缓冲区
            byte[] data = new byte[port.BytesToRead];
            //从串口读取数据
            port.Read(data, 0, data.Length);
            //处理收到的数据
            DataReceived(ref data, data.Length);
        }
#endif
        private void DataReceived(ref byte[] data, int len)
        {
            try
            {
                if (ReadCnt > ReadBuffer.Length)
                {
                    ReadCnt = ReadBuffer.Length;
                }
                if (ReadCnt + len > ReadBuffer.Length)
                {//防止数据溢出
                    len = ReadBuffer.Length - ReadCnt;
                }
                Array.Copy(data, 0, ReadBuffer, ReadCnt, len);

                ReadCnt += len;
                if (ReadBuffer[0] == 'K')
                {
                    if (ReadCnt > 4 && ReadCnt >= ReadBuffer[1])
                    {
                        ReadCnt = ReadBuffer[1];
                        UInt16 crc = CrcCheck.crc16(ReadBuffer, ReadCnt - 2);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(ReadBuffer, ReadCnt - 2, 2);
                        }
                        if (crc == BitConverter.ToUInt16(ReadBuffer, ReadCnt - 2))
                        {
                            //在主界面线程处理收到的数据
                            byte[] ReDatas = new byte[ReadCnt];
                            Array.Copy(ReadBuffer, ReDatas, ReadCnt);
                            this.Dispatcher.BeginInvoke(new PortCallback(ProcessPortData), ReDatas);
                        }
                    }
                    else
                    {
                        return;
                    }
                }
                ClearReceiveBuf();
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
                System.Diagnostics.Debug.Assert(false, s);
            }
            ReadCnt = 0;
            Array.Clear(ReadBuffer, 0, ReadBuffer.Length);
        }

        void SendCrcData(byte[] datas)
        {
            UInt16 crc = CrcCheck.crc16(datas, datas.Length - 2);
            byte[] buf = BitConverter.GetBytes(crc);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(buf);
            }
            Array.Copy(buf, 0, datas, datas.Length - 2, 2);
            m_sdata = datas;
            SendData(datas);
        }
        void SendCmd(ProtocolCmd cmd, byte param)
        {
            byte[] datas = new byte[7] { (byte)('K'), 7, (byte)cmd, param, 0, 0, 0 };
            SendCrcData(datas);
        }
        void SendCmd(ProtocolCmd cmd, UInt16 param)
        {
            byte[] datas = new byte[7] { (byte)('K'), 7, (byte)cmd, (byte)(param >> 8), (byte)(param & 0xFF), 0, 0 };
            SendCrcData(datas);
        }

        void SendLogoString(int index)
        {
            System.Diagnostics.Trace.WriteLine(String.Format("SendLogoString:id {0:D}", index));
            m_sdata = new byte[16 + 7];
            Array.Clear(m_sdata, 0, m_sdata.Length);
            m_sdata[0] = (byte)'K';
            m_sdata[1] = (byte)m_sdata.Length;
            m_sdata[2] = (byte)ProtocolCmd.PCMD_LOGO_WRITE;
            m_sdata[3] = (byte)index;//
            m_sdata[4] = 0;
            Array.Copy(logo_string, index, m_sdata, 5, 16);
            SendCrcData(m_sdata);
        }

        public static byte[] GetGB2312EncodeData(string str_uni, int buf_size)
        {
            Encoding gb2312 = Encoding.GetEncoding("GB2312");
            byte[] data = Encoding.Default.GetBytes(str_uni);
            data = Encoding.Convert(Encoding.Default, gb2312, data);
            string serv = gb2312.GetString(data);
            serv = SubStringByBytes(serv, buf_size, gb2312);
            return gb2312.GetBytes(serv);
        }
        public static string GetDefaultEncodeString(byte[] str_gb2312)
        {
            //byte[] data = new byte[11] { (byte)'S', (byte)'S', (byte)'S', (byte)'S', (byte)'S', 0, 0, 0, (byte)'S', 0, 0 };
            int id = Array.IndexOf(str_gb2312, (byte)'\0');
            if (id > 0)
            {
                byte[] data = new byte[id];
                Array.Copy(str_gb2312, data, data.Length);
                str_gb2312 = data;
                try
                {
                    Encoding gb2312 = Encoding.GetEncoding("GB2312");
                    str_gb2312 = Encoding.Convert(gb2312, Encoding.Default, str_gb2312);
                    return gb2312.GetString(str_gb2312);
                }
                catch (Exception)
                {
                    System.Diagnostics.Trace.WriteLine("Encoding error");
                }
            }
            return "";
        }

        /// <summary>
        /// 按字节数截取字符串的方法(比SubString好用)
        /// </summary>
        /// <param name="source">要截取的字符串（可空）</param>
        /// <param name="NumberOfBytes">要截取的字节数</param>
        /// <param name="encoding">System.Text.Encoding</param>
        /// <returns></returns>
        public static string SubStringByBytes(string source, int NumberOfBytes, System.Text.Encoding encoding)
        {
            if (string.IsNullOrWhiteSpace(source) || source.Length == 0)
                return source;

            if (encoding.GetBytes(source).Length <= NumberOfBytes)
                return source;

            long tempLen = 0;
            StringBuilder sb = new StringBuilder();
            foreach (var c in source)
            {
                Char[] _charArr = new Char[] { c };
                byte[] _charBytes = encoding.GetBytes(_charArr);
                if ((tempLen + _charBytes.Length) > NumberOfBytes)
                {
                    break;
                }
                else
                {
                    tempLen += _charBytes.Length;
                    sb.Append(encoding.GetString(_charBytes));
                }
            }
            return sb.ToString();
        }

        void SendPrefix()
        {
            System.Diagnostics.Trace.WriteLine(String.Format("SendPrefix:{0}", txboxNumPrefix.Text));
            m_sdata = new byte[24];
            Array.Clear(m_sdata, 0, m_sdata.Length);
            m_sdata[0] = (byte)'K';
            m_sdata[1] = (byte)m_sdata.Length;
            m_sdata[2] = (byte)ProtocolCmd.PCMD_WRITE_SERVICE;
            m_sdata[3] = 0;
            m_sdata[4] = 0;
            byte[] str = GetGB2312EncodeData(txboxNumPrefix.Text, 16);
            Array.Copy(str, 0, m_sdata, 5, str.Length > 16 ? 16 : str.Length);
            m_sdata[21] = (byte)'\0';
            SendCrcData(m_sdata);
        }

        void ReadPager(UInt16 i)
        {
            byte[] datas = new byte[9] { (byte)('K'), 9, (byte)ProtocolCmd.PCMD_READ_PAGER, 0, 0, 0, 0, 0, 0 };
            System.Diagnostics.Trace.WriteLine(string.Format("read pager:{0:D}", i));
            Array.Copy(BitConverter.GetBytes(i), 0, datas, 5, 2);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(datas, 5, 2);
            }
            SendCrcData(datas);
        }

        enum pager_type_e
        {
            PT_PAGER,
            PT_REMOTE_CTR,
            PT_ALARM,
            PT_CANCEL,
            PT_OTHER,
        };

        enum ProtocolCmd
        {
            PCMD_TIME = 1,
            PCMD_BEGIN_WRITE,
            PCMD_READ_SETTING,
            PCMD_READ_SERVICE,
            PCMD_READ_LOGO,
            PCMD_READ_PAGER,
            PCMD_CLEAR_PAGERS,
            PCMD_RESET_FACTORY,
            PCMD_HEART_BEAT,
            PCMD_REG_REMOTE_CTL,
            PCMD_REG_PAGER,
            PCMD_DEL_PAGER,

            PCMD_CALL = 0x91,          //呼叫
            PCMD_CANCEL = 0x92,        //应答

            PCMD_WRITE_SETTING = PCMD_READ_SETTING | 0X80,
            PCMD_WRITE_SERVICE = PCMD_READ_SERVICE | 0X80,
            PCMD_LOGO_WRITE = PCMD_READ_LOGO | 0X80,
            PCMD_END,
        }

        private UInt16 m_read_pager_id;
        private byte[] logo_string = new byte[129];

        private void ProcessPortData(ref byte[] data)
        {
            try
            {
                switch ((ProtocolCmd)data[2])
                {
                    case ProtocolCmd.PCMD_TIME:
                        System.Diagnostics.Trace.WriteLine("PCMD_TIME");
                        if (data[4] != 0)
                        {
                            EndTrans();
                            MessageBox.Show(this, Application.Current.FindResource("keySetTimeSuccess").ToString());//
                        }
                        break;
                    case ProtocolCmd.PCMD_READ_SETTING:
                        System.Diagnostics.Trace.WriteLine("PCMD_READ_SETTING");
                        m_timer.Start();
                        PushCallFront = (UInt32)data[5]; ;
                        SoundType = (UInt32)data[6];
                        nudReportTimes.Value = (decimal)data[7];
                        TemorrowResetNumber = (data[8] != 0);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(data, 9, 2);
                            Array.Reverse(data, 11, 2);
                            Array.Reverse(data, 13, 2);
                            Array.Reverse(data, 15, 2);
                            Array.Reverse(data, 17, 2);
                        }
                        nudTimeoutTime.Value = BitConverter.ToUInt16(data, 9);
                        nudStartNum.Value = BitConverter.ToUInt16(data, 11);
                        nudEndNum.Value = BitConverter.ToUInt16(data, 13);
                        nudEliminationTime.Value = BitConverter.ToUInt16(data, 15);
                        nudRotationTime.Value = BitConverter.ToUInt16(data, 17);
                        
                        Volume = (UInt32)data[19];
                        TextColor = data[20];
                        PowerDownMemory = (data[21] != 0);
                        NumberFormat = (UInt32)data[22];
                        Modulation = data[23];
                        RFFreqID = data[24];
                        LanguageId = (UInt32)data[25];

                        SendCmd(ProtocolCmd.PCMD_READ_SERVICE, 0);
                        this.TransProgressBar.Value++;
                        break;
                    case ProtocolCmd.PCMD_READ_SERVICE:
                        System.Diagnostics.Trace.WriteLine("PCMD_READ_SERVICE");
                        m_timer.Start();
                        byte[] buf = new byte[17];
                        Array.Copy(data, 5, buf, 0, buf.Length);
                        txboxNumPrefix.Text = GetDefaultEncodeString(buf);
                        SendCmd(ProtocolCmd.PCMD_READ_LOGO, 0);
                        Array.Clear(logo_string, 0, logo_string.Length);
                        this.TransProgressBar.Value++;
                        break;
                    case ProtocolCmd.PCMD_READ_LOGO:
                        System.Diagnostics.Trace.WriteLine("PCMD_READ_LOGO");
                        m_timer.Stop();
                        m_timer.Start();
                        if (data[3] < logo_string.Length - 16)
                        {
                            Array.Copy(data, 5, logo_string, data[3], 16);
                            if (data[3] + 16 < logo_string.Length - 1)
                            {
                                SendCmd(ProtocolCmd.PCMD_READ_LOGO, (byte)(data[3] + 16));
                                break;
                            }
                            else
                            {
                                this.LogoTextBox.Text = GetDefaultEncodeString(logo_string);
                            }
                        }
                        pagerDatatable.Clear();
                        m_read_pager_id = 0;
                        ReadPager(0);
                        this.TransProgressBar.Value++;
                        break;
                    case ProtocolCmd.PCMD_READ_PAGER:
                        System.Diagnostics.Trace.WriteLine("PCMD_READ_PAGER");
                        if (0 == data[4])
                            break;
                        if (data.Length >= 23 && 0 != data[3])
                        {
                            m_timer.Stop();
                            m_timer.Start();
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(data, 5, 2);
                                Array.Reverse(data, 19, 2);
                            }
                            UInt16 id = BitConverter.ToUInt16(data, 5);
                            UInt16 pre_id = BitConverter.ToUInt16(data, 19);
                            if (pre_id != m_read_pager_id)
                            {
                                //确保不重复接收
                                ReadPager(m_read_pager_id);
                                break;
                            }
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(data, 7, 4);
                            }
                            this.TransProgressBar.Value = 19 + id / (0x200 / 20);
                            UInt32 code = BitConverter.ToUInt32(data, 7) & 0x00FFFFF0;
                            byte[] arr_name = new byte[5];
                            Array.Clear(arr_name, 0, arr_name.Length);
                            Array.Copy(data, 11, arr_name, 0, 4);
                            DataRow dr = pagerDatatable.NewRow();
                            dr["pager_index"] = id;
                            dr["pager_code"] = code;// string.Format("{0:X8}", code);
                            dr["pager_name"] = GetDefaultEncodeString(arr_name);
                            dr["pager_type"] = data[15];
                            dr["pager_status"] = data[16];
                            dr["pager_service"] = data[17];
                            dr["pager_color"] = data[18];
                            pagerDatatable.Rows.Add(dr);
                            if (++id < 0x200)
                            {
                                m_read_pager_id = id;
                                ReadPager(id);
                                break;
                            }
                        }
                        else if(data.Length < 9)
                        {
                            break;
                        }
                        SendCmd(ProtocolCmd.PCMD_END, 0);
                        this.TransProgressBar.Value = this.TransProgressBar.Maximum - 1;
                        break;
                    case ProtocolCmd.PCMD_BEGIN_WRITE:
                        System.Diagnostics.Trace.WriteLine("PCMD_BEGIN_WRITE");
                        m_timer.Start();
                        m_sdata = new byte[28];
                        Array.Clear(m_sdata, 0, m_sdata.Length);
                        m_sdata[0] = (byte)'K';
                        m_sdata[1] = (byte)m_sdata.Length;
                        m_sdata[2] = (byte)ProtocolCmd.PCMD_WRITE_SETTING;
                        m_sdata[3] = 0;
                        m_sdata[4] = 0;
                        m_sdata[5] = Convert.ToByte(PushCallFront);
                        m_sdata[6] = (byte)SoundType;
                        m_sdata[7] = (byte)nudReportTimes.Value;
                        m_sdata[8] = Convert.ToByte(TemorrowResetNumber);
                        Array.Copy(BitConverter.GetBytes((UInt16)nudTimeoutTime.Value), 0, m_sdata, 9, 2);
                        Array.Copy(BitConverter.GetBytes((UInt16)nudStartNum.Value), 0, m_sdata, 11, 2);
                        Array.Copy(BitConverter.GetBytes((UInt16)nudEndNum.Value), 0, m_sdata, 13, 2);
                        Array.Copy(BitConverter.GetBytes((UInt16)nudEliminationTime.Value), 0, m_sdata, 15, 2);
                        Array.Copy(BitConverter.GetBytes((UInt16)nudRotationTime.Value), 0, m_sdata, 17, 2);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(m_sdata, 9, 2);
                            Array.Reverse(m_sdata, 11, 2);
                            Array.Reverse(m_sdata, 13, 2);
                            Array.Reverse(m_sdata, 15, 2);
                            Array.Reverse(m_sdata, 17, 2);
                        }
                        m_sdata[19] = (byte)Volume;
                        m_sdata[20] = (byte)TextColor;
                        m_sdata[21] = Convert.ToByte(PowerDownMemory);
                        m_sdata[22] = Convert.ToByte(NumberFormat);
                        m_sdata[23] = (byte)Modulation;
                        m_sdata[24] = (byte)RFFreqID;
                        m_sdata[25] = (byte)LanguageId;
                        SendCrcData(m_sdata);
                        this.TransProgressBar.Value++;
                        break;
                    case ProtocolCmd.PCMD_WRITE_SETTING:
                        System.Diagnostics.Trace.WriteLine("PCMD_WRITE_SETTING");
                        m_timer.Start();
                        SendPrefix();
                        this.TransProgressBar.Value++;
                        break;
                    case ProtocolCmd.PCMD_WRITE_SERVICE:
                        System.Diagnostics.Trace.WriteLine("PCMD_WRITE_SERVICE");
                        if (data[4] != 0)//ACK
                        {
                            byte[] str = GetGB2312EncodeData(this.LogoTextBox.Text, logo_string.Length);
                            Encoding gb2312 = Encoding.GetEncoding("GB2312");
                            str = Encoding.Convert(Encoding.Default, gb2312, str);
                            Array.Clear(logo_string, 0, logo_string.Length);
                            Array.Copy(str, 0, logo_string, 0, str.Length > logo_string.Length ? logo_string.Length : str.Length);
                            SendLogoString(0);
                            this.TransProgressBar.Value++;
                        }
                        break;
                    case ProtocolCmd.PCMD_LOGO_WRITE:
                        System.Diagnostics.Trace.WriteLine("PCMD_LOGO_WRITE");
                        if (data[4] != 0)//ACK
                        {
                            if (data[3] + 16 < logo_string.Length - 1)
                            {
                                m_timer.Start();//
                                SendLogoString(data[3] + 16);
                            }
                            else
                            {
                                SendCmd(ProtocolCmd.PCMD_END, 0);
                            }
                            this.TransProgressBar.Value++;
                        }
                        break;
                    case ProtocolCmd.PCMD_RESET_FACTORY:
                        System.Diagnostics.Trace.WriteLine("PCMD_RESET_FACTORY");
                        if (data[4] != 0)
                        {
                            EndTrans();
                            MessageBox.Show(this, Application.Current.FindResource("keyResetFactorySuccess").ToString());//"读取成功"
                        }
                        break;
                    case ProtocolCmd.PCMD_END:
                        EndTrans();
                        this.TransProgressBar.Value = this.TransProgressBar.Maximum;
                        if (m_read_setting)
                        {
                            MessageBox.Show(this, Application.Current.FindResource("keyReadSuccess").ToString()//"读取成功"
                                    , Application.Current.FindResource("keyRead").ToString()//
                                    , MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        else
                        {
                            MessageBox.Show(this, Application.Current.FindResource("keyWriteSuccess").ToString()//"写入成功"
                                    , Application.Current.FindResource("keyWrite").ToString()//
                                    , MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        break;
                    case ProtocolCmd.PCMD_HEART_BEAT:
                        if (data[4] != 0)
                        {
                            m_retry_cnt = 0;
                            this.TransProgressBar.Value++;
                            if (this.TransProgressBar.Value >= this.TransProgressBar.Maximum)
                            {
                                EndTrans();
                            }
                        }
                        else
                        {
                            SendCmd(ProtocolCmd.PCMD_HEART_BEAT, 0);
                        }
                        break;
                    case ProtocolCmd.PCMD_REG_PAGER:
                        if (data[3] != 0 && data[4] != 0)
                        {
                            EndTrans();
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(data, 5, 2);
                                Array.Reverse(data, 7, 4);
                            }
                            UInt16 id = BitConverter.ToUInt16(data, 5);
                            if (id < 0x200)
                            {
                                this.TransProgressBar.Value = this.TransProgressBar.Maximum;

                                UInt32 code = BitConverter.ToUInt32(data, 7) & 0x00FFFFF0;
                                byte[] arr_name = new byte[5];
                                Array.Clear(arr_name, 0, arr_name.Length);
                                Array.Copy(data, 11, arr_name, 0, 4);
                                string region = GetDefaultEncodeString(arr_name);
                                DataRow[] founds = pagerDatatable.Select(string.Format("pager_index = {0:D}", id));
                                DataRow dr;
                                if (founds.Length == 0)
                                {
                                    dr = pagerDatatable.NewRow();
                                    pagerDatatable.Rows.Add(dr);
                                }
                                else
                                {
                                    dr = founds[0];
                                }
                                dr["pager_index"] = id;
                                dr["pager_code"] = code;// string.Format("{0:X8}", code);
                                dr["pager_name"] = region;
                                dr["pager_type"] = data[15];
                                dr["pager_status"] = data[16];
                                dr["pager_service"] = data[17];
                                dr["pager_color"] = data[18];
                                MessageBox.Show(this, Application.Current.FindResource("keyRegSuccess").ToString()//
                                    , Application.Current.FindResource("keyRegPager").ToString()//
                                    , MessageBoxButton.OK, MessageBoxImage.Information);
                            }
                            else
                            {
                                MessageBox.Show(this, Application.Current.FindResource("keyRegFailed").ToString()//
                                    , Application.Current.FindResource("keyRegPager").ToString()//
                                    , MessageBoxButton.OK, MessageBoxImage.Information);
                            }
                        }
                        break;
                    case ProtocolCmd.PCMD_DEL_PAGER:
                        if (data[4] != 0 && data.Length >= 21)
                        {
                            EndTrans();
                            if(data[3] != 0)
                            {
                                if (BitConverter.IsLittleEndian)
                                {
                                    Array.Reverse(data, 5, 2);
                                    Array.Reverse(data, 7, 4);
                                }
                                UInt16 id = BitConverter.ToUInt16(data, 5);
                                if (id < 0x200)
                                {
                                    this.TransProgressBar.Value = this.TransProgressBar.Maximum;

                                    UInt32 code = BitConverter.ToUInt32(data, 7) & 0x00FFFFF0;
                                    byte[] arr_name = new byte[5];
                                    Array.Clear(arr_name, 0, arr_name.Length);
                                    Array.Copy(data, 11, arr_name, 0, 4);
                                    string region = GetDefaultEncodeString(arr_name);
                                    DataRow[] founds = pagerDatatable.Select(string.Format("pager_index = {0:D}", id));
                                    if (founds.Length != 0)
                                    {
                                        DataRow dr = founds[0];
                                        dr["pager_index"] = id;
                                        dr["pager_code"] = code;// string.Format("{0:X8}", code);
                                        dr["pager_name"] = region;
                                        dr["pager_type"] = data[15];
                                        dr["pager_status"] = data[16];
                                        dr["pager_service"] = data[17];
                                        dr["pager_color"] = data[18];
                                    }
                                    MessageBox.Show(this, Application.Current.FindResource("keyDelSuccess").ToString()//
                                            , Application.Current.FindResource("keyRegPager").ToString()//
                                            , MessageBoxButton.OK, MessageBoxImage.Information);
                                    break;
                                }
                            }
                            MessageBox.Show(this, Application.Current.FindResource("keyRegFailed").ToString()//
                                    , Application.Current.FindResource("keyDelFailed").ToString()//
                                    , MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        break;
                }
            }
            catch (Exception e)
            {
                EndTrans();
                MessageBox.Show(this, e.Message);//
            }
        }

        private void ClearReceiveBuf()
        {
#if USE_SERIALPORT
            port.DiscardInBuffer();
#else
            comport.ClearReceiveBuf();
#endif
        }

        private void CloseSerialPort()
        {
#if USE_SERIALPORT
            port.Close();
#else
            comport.Close();
#endif
        }

        private bool OpenSerialPort()
        {
#if USE_SERIALPORT
            if (!port.IsOpen)
            {
                if (m_port_name == null || m_port_name.Length == 0)
                {
                    MessageBox.Show(this, Application.Current.FindResource("keyPlsSelPort").ToString());//
                    return false;
                }
                try
                {
                    port.PortName = m_port_name;
                    port.Open();
                }
                catch (Exception)
                {
                    string format = Application.Current.FindResource("keyOpenPortFailed").ToString();
                    format = string.Format(format, m_port_name);
                    MessageBox.Show(format //"串口未开启"
                    , Application.Current.FindResource("keyError").ToString() //"错误"
                    , MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
#else
            if (!comport.Opened)
            {
                if (0 != comport.Open())
                {
                    MessageBox.Show(Application.Current.FindResource("keyOpenPortFailed").ToString() //"串口未开启"
                    , Application.Current.FindResource("keyError").ToString() //"错误"
                    , MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            }
#endif
            return true;
        }

        bool m_read_setting;
        bool m_communicating = false;
        int m_retry_cnt;
        private byte[] m_sdata;
        private DispatcherTimer m_timer;

        public bool SendData(Byte[] data)
        {
            System.Diagnostics.Debug.Assert(data != null);
#if USE_SERIALPORT
            if (port.IsOpen)
            {
                try
                {
                    //将消息传递给串口
                    port.Write(data, 0, data.Length);
                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(this, ex.Message, Application.Current.FindResource("keyPortClosed").ToString() //"发送失败"
                        , MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
#else
            if (comport.Opened)
            {
                //将消息传递给串口
                if (comport.Write(ref data) != -1)
                {
                    return true;
                }
                else
                {
                    System.Diagnostics.Debug.Assert(false, "comport.Write failed!");
                    return false;
                }
            }
#endif
            else
            {
                MessageBox.Show(this, Application.Current.FindResource("keyPortClosed").ToString() //"串口未开启"
                    , Application.Current.FindResource("keyError").ToString() //"错误"
                    , MessageBoxButton.OK, MessageBoxImage.Error);
            }

            return false;
        }

        private void BtnReadClick(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort())
            {
                m_retry_cnt = 0;
                m_read_setting = true;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                SendCmd(ProtocolCmd.PCMD_READ_SETTING, 0);//SendCmd(ProtocolCmd.PCMD_BEGIN_WRITE, 0);
                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 56;
            }
        }


        private void BtnWriteClick(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort())
            {
                this.CboPort.Focus();
                m_retry_cnt = 0;
                m_read_setting = false;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                SendCmd(ProtocolCmd.PCMD_BEGIN_WRITE, 1);
                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 36;
            }
        }
        private void BtnkeyResetFactoryClick(object sender, RoutedEventArgs e)
        {
            if (!m_communicating)
            {
                if (MessageBoxResult.Yes == MessageBox.Show(this, Application.Current.FindResource("keyConfirmResetFactory").ToString(),
                    Application.Current.FindResource("keyAppName").ToString(), MessageBoxButton.YesNo))
                {
                    if (OpenSerialPort())
                    {
                        m_retry_cnt = 0;
                        m_read_setting = false;
                        m_communicating = true;
                        RootGrid.IsEnabled = false;
                        SendCmd(ProtocolCmd.PCMD_RESET_FACTORY, 0);
                        m_timer.Start();
                        this.TransProgressBar.Value = 0;
                        this.TransProgressBar.Maximum = 20;
                    }
                }
            }
        }
        //typedef struct tm
        //{
        //    u16 tm_sec; /* 秒–取值区间为[0,59] */
        //    u16 tm_min; /* 分 - 取值区间为[0,59] */
        //    u16 tm_hour; /* 时 - 取值区间为[0,23] */
        //    u16 tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
        //    u16 tm_mon; /* 月份（从一月开始，0代表一月） - 取值区间为[0,11] */
        //    u16 tm_year; /* 年份，其值从1900开始 */
        //    u16 tm_wday; /* 星期–取值区间为[0,6]，其中0代表星期天，1代表星期一，以此类推 */
        //    //int tm_yday; /* 从每年的1月1日开始的天数–取值区间为[0,365]，其中0代表1月1日，1代表1月2日，以此类推 */
        //    //int tm_isdst; /* 夏令时标识符，实行夏令时的时候，tm_isdst为正。不实行夏令时的进候，tm_isdst为0；不了解情况时，tm_isdst()为负。*/
        //    //long int tm_gmtoff; /*指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数*/
        //    //const char* tm_zone; /*当前时区的名字(与环境变量TZ有关)*/
        //}
        //tm_t;
        private void ButtonSetTime_Click(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort())
            {
                m_retry_cnt = 0;
                m_read_setting = false;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                DateTime dt = DateTime.Now;
                m_sdata = new byte[21];
                Array.Clear(m_sdata, 0, m_sdata.Length);
                m_sdata[0] = (byte)'K';
                m_sdata[1] = (byte)m_sdata.Length;
                m_sdata[2] = (byte)ProtocolCmd.PCMD_TIME;
                m_sdata[3] = 0;//Service id
                m_sdata[4] = 0;
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Second), 0, m_sdata, 5, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Minute), 0, m_sdata, 7, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Hour), 0, m_sdata, 9, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Day), 0, m_sdata, 11, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Month), 0, m_sdata, 13, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.Year), 0, m_sdata, 15, 2);
                Array.Copy(BitConverter.GetBytes((UInt16)dt.DayOfWeek), 0, m_sdata, 17, 2);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(m_sdata, 5, 2);
                    Array.Reverse(m_sdata, 7, 2);
                    Array.Reverse(m_sdata, 9, 2);
                    Array.Reverse(m_sdata, 11, 2);
                    Array.Reverse(m_sdata, 13, 2);
                    Array.Reverse(m_sdata, 15, 2);
                    Array.Reverse(m_sdata, 17, 2);
                }
                SendCrcData(m_sdata);

                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 20;
            }
        }

        private bool m_registing = false;

        private void ButtonRegPager_Click(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort())
            {
                m_retry_cnt = 0;
                m_read_setting = false;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                m_registing = true;
                //状态栏显示：请按呼叫器
                this.TextBlkTestServiceState.Text = Application.Current.FindResource("keyRegisting").ToString();
                this.TextBlkTestServiceState.Visibility = Visibility;

                m_sdata = new byte[15];
                Array.Clear(m_sdata, 0, m_sdata.Length);
                m_sdata[0] = (byte)'K';
                m_sdata[1] = (byte)m_sdata.Length;
                m_sdata[2] = (byte)ProtocolCmd.PCMD_REG_PAGER;
                m_sdata[3] = 0;//
                m_sdata[4] = 0;
                Array.Copy(BitConverter.GetBytes((UInt16)nudEndNum.Value), 0, m_sdata, 5, 2);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(m_sdata, 5, 2);
                }
                byte[] str = GetGB2312EncodeData(txboxRegion.Text, 4);
                Array.Copy(str, 0, m_sdata, 7, str.Length > 4 ? 4 : str.Length);
                m_sdata[11] = (byte)cboRegServiceSound.SelectedIndex;
                m_sdata[12] = (byte)cboRegServiceColor.SelectedIndex;
                SendCrcData(m_sdata);
                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 10;
            }
            else if (m_registing)
            {
                EndTrans();
            }
        }

        private void ButtonDelPager_Click(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort() && PagerGrid.SelectedIndex != -1)
            {
                m_retry_cnt = 0;
                m_read_setting = false;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                m_registing = true;
                //状态栏显示：删除呼叫器
                this.TextBlkTestServiceState.Text = Application.Current.FindResource("keyDelPager").ToString();
                this.TextBlkTestServiceState.Visibility = Visibility;

                DataRow row = pagerDatatable.Rows[PagerGrid.SelectedIndex];
                UInt16 id = (UInt16)row["pager_index"];
                UInt32 code = (UInt32)row["pager_code"];
                string name = (string)row["pager_name"];
                
                m_sdata = new byte[21];
                Array.Clear(m_sdata, 0, m_sdata.Length);
                m_sdata[0] = (byte)'K';
                m_sdata[1] = (byte)m_sdata.Length;
                m_sdata[2] = (byte)ProtocolCmd.PCMD_DEL_PAGER;
                m_sdata[3] = 0;//
                m_sdata[4] = 0;
                Array.Copy(BitConverter.GetBytes(id), 0, m_sdata, 5, 2);
                Array.Copy(BitConverter.GetBytes(code), 0, m_sdata, 7, 4);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(m_sdata, 5, 2);
                    Array.Reverse(m_sdata, 7, 4);
                }
                byte[] str = GetGB2312EncodeData(name, 4);
                Array.Copy(str, 0, m_sdata, 11, str.Length > 4 ? 4 : str.Length);
                m_sdata[15] = (byte)row["pager_type"];
                m_sdata[16] = (byte)row["pager_status"];
                m_sdata[17] = (byte)row["pager_service"];
                m_sdata[18] = (byte)row["pager_color"];
                SendCrcData(m_sdata);
                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 20;
            }
            else if (m_registing)
            {
                EndTrans();
            }
        }

        private void BtnRegRemoteCtl_Click(object sender, RoutedEventArgs e)
        {
            if (!m_communicating && OpenSerialPort())
            {
                m_retry_cnt = 0;
                m_read_setting = false;
                m_communicating = true;
                RootGrid.IsEnabled = false;
                m_registing = true;
                //状态栏显示：请按呼叫器
                this.TextBlkTestServiceState.Text = Application.Current.FindResource("keyRegisting").ToString();
                this.TextBlkTestServiceState.Visibility = Visibility;
                SendCmd(ProtocolCmd.PCMD_REG_REMOTE_CTL, 0);
                m_timer.Start();
                this.TransProgressBar.Value = 0;
                this.TransProgressBar.Maximum = 10;
            }
        }


        void EndTrans()
        {
            m_retry_cnt = 0;
            m_timer.Stop();
            CloseSerialPort();
            RootGrid.IsEnabled = true;
            m_communicating = false;
            if (m_registing)
            {
                m_registing = false;
                this.TextBlkTestServiceState.Visibility = Visibility.Hidden;
            }
        }

        private void TransTimeOut(object sender, EventArgs e)
        {
            System.Diagnostics.Trace.WriteLine("TransTimeOut");
            if (++m_retry_cnt > 3)
            {
                EndTrans();
                MessageBox.Show(this, Application.Current.FindResource("keyNoReponse").ToString()//"设备超时无反应，请检查端口设置！"
                    , Application.Current.FindResource("keyError").ToString()//"失败"
                    , MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            SendData(m_sdata);
        }

        private UInt32 m_sound_type;
        public UInt32 SoundType
        {
            get { return m_sound_type; }
            set
            {
                if (m_sound_type != value)
                {
                    m_sound_type = value;
                    RaiseOnPropertyChanged("SoundType");
                }
            }
        }

        private UInt32 m_text_color = 0;
        public UInt32 TextColor
        {
            get
            {
                return m_text_color;
            }
            set
            {
                if (m_text_color != value)
                {
                    m_text_color = value;
                    RaiseOnPropertyChanged("TextColor");
                }
            }
        }

        private UInt32 m_modulation;
        public UInt32 Modulation
        {
            get
            {
                return m_modulation;
            }
            set
            {
                if (m_modulation != value)
                {
                    m_modulation = value;
                    RaiseOnPropertyChanged("Modulation");
                }
            }
        }

        private UInt32 m_rf_freq_id;
        public UInt32 RFFreqID
        {
            get
            {
                return m_rf_freq_id;
            }
            set
            {
                if (m_rf_freq_id != value)
                {
                    m_rf_freq_id = value;
                    RaiseOnPropertyChanged("RFFreqID");
                }
            }
        }

        private UInt32 m_language_id;
        public UInt32 LanguageId
        {
            get
            {
                return m_language_id;
            }
            set
            {
                if (m_language_id != value)
                {
                    m_language_id = value;
                    RaiseOnPropertyChanged("LanguageId");
                }
            }
        }

        private UInt32 m_volume;
        public UInt32 Volume
        {
            get
            {
                return m_volume;
            }
            set
            {
                if (m_volume != value)
                {
                    m_volume = value;
                    RaiseOnPropertyChanged("Volume");
                }
            }
        }

        private UInt32 m_number_format;
        public UInt32 NumberFormat
        {
            get { return m_number_format; }
            set
            {
                m_number_format = value;
                RaiseOnPropertyChanged("NumberFormat");
            }
        }

        private bool m_temorrow_reset_number;
        public bool TemorrowResetNumber
        {
            get { return m_temorrow_reset_number; }
            set
            {
                m_temorrow_reset_number = value;
                RaiseOnPropertyChanged("TemorrowResetNumber");
            }
        }


        private bool m_power_down_memory;
        public bool PowerDownMemory
        {
            get { return m_power_down_memory; }
            set
            {
                m_power_down_memory = value;
                RaiseOnPropertyChanged("PowerDownMemory");
            }
        }

        private uint m_push_call_list_front;
        public uint PushCallFront
        {
            get { return m_push_call_list_front; }
            set
            {
                if (m_push_call_list_front != value)
                {
                    m_push_call_list_front = value;
                    RaiseOnPropertyChanged("PushCallFront");
                }
            }
        }

        private string m_port_name;
        public string PortName
        {
#if USE_SERIALPORT
            get
            {
                return m_port_name;
            }
            set
            {
                if (null == value)
                {
                    if (port.IsOpen)
                        port.Close();
                    m_port_name = "";
                    CboPort.SelectedIndex = -1;
                    RaiseOnPropertyChanged("PortName");
                }
                else if (value.Length > 0 && m_port_name != value && !port.IsOpen)
                {
                    m_port_name = value;
                    xBaseSetting.SetAttribute("COM", value);
                    RaiseOnPropertyChanged("PortName");
                }
            }
#else
            get
            {
                return comport.Port;
            }
            set
            {
                if (value.Length > 0 && comport.Port != value)
                {
                    comport.Port = value;
                    xBaseSetting.SetAttribute("COM", value);
                    RaiseOnPropertyChanged("PortName");
                }
            }
#endif
        }

        public String[] ports;
        public String[] CommPortList
        {
            get
            {
                return ports;
            }
            set
            {
                ports = value;
                RaiseOnPropertyChanged("CommPortList");
            }
        }

        private Pair[] color_list;

        public Pair[] ColorList
        {
            get
            {
                return color_list;
            }
            set
            {
                color_list = value;
                RaiseOnPropertyChanged("ColorList");
            }
        }



        #region ProperChangedEvent
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaiseOnPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (null != propertyChanged)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        private List<Services> ServiceList = new List<Services>();

#if USE_SERIALPORT
        private SerialPort port = new SerialPort();
#else
        private CommPort comport = new CommPort();
#endif


        private void Window_Closing(object sender, CancelEventArgs e)
        {
            xBaseSetting.SetAttribute("PushCallFront", PushCallFront.ToString());
            xBaseSetting.SetAttribute("NumPrefix", txboxNumPrefix.Text);
            xBaseSetting.SetAttribute("TextColor", TextColor.ToString());
            xBaseSetting.SetAttribute("SoundType", SoundType.ToString());
            xBaseSetting.SetAttribute("Volume", Volume.ToString());
            xBaseSetting.SetAttribute("LanguageId", LanguageId.ToString());
            xBaseSetting.SetAttribute("Modulation", Modulation.ToString());
            xBaseSetting.SetAttribute("RFFreqID", RFFreqID.ToString());
            xBaseSetting.SetAttribute("RotationTime", nudEliminationTime.Value.ToString());
            xBaseSetting.SetAttribute("EliminationTime", nudEliminationTime.Value.ToString());
            xBaseSetting.SetAttribute("ReportTimes", nudReportTimes.Value.ToString());
            xBaseSetting.SetAttribute("TimeoutTime", nudTimeoutTime.Value.ToString());
            xBaseSetting.SetAttribute("StartNumber", nudStartNum.Value.ToString());
            xBaseSetting.SetAttribute("MaxNumber", nudEndNum.Value.ToString());
            xBaseSetting.SetAttribute("TemorrowResetNumber", TemorrowResetNumber.ToString());
            xBaseSetting.SetAttribute("NumberFormat", NumberFormat.ToString());
            xBaseSetting.SetAttribute("PowerDownMemory", PowerDownMemory.ToString());//
            xBaseSetting.SetAttribute("logo", this.LogoTextBox.Text);
            xDoc.Save("queue_system_setting.dat");
            if (pagerDatatable.Rows.Count > 0)
            {
                pagerDatatable.WriteXml("pagers_data.dat", false);
            }
        }

        private void ToolBar_Loaded(object sender, RoutedEventArgs e)
        {
            //去掉ToolBar右边默认的扩展图标
            ToolBar toolBar = sender as ToolBar;

            var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;

            if (overflowGrid != null)
            {
                overflowGrid.Visibility = Visibility.Collapsed;
            }
            var mainPanelBorder = toolBar.Template.FindName("MainPanelBorder", toolBar) as FrameworkElement;

            if (mainPanelBorder != null)
            {
                mainPanelBorder.Margin = new Thickness(0);
            }
        }

        private void BtnLanguage_Click(object sender, RoutedEventArgs e)
        {
            if (culture_en == Properties.Resources.Culture)
            {
                Properties.Resources.Culture = culture_ch;
            }
            else
            {
                Properties.Resources.Culture = culture_en;
            }
            ResourceDictionary res = Application.Current.Resources.MergedDictionaries[0];
            Application.Current.Resources.MergedDictionaries.Remove(res);
            Application.Current.Resources.MergedDictionaries.Add(res);
            PagerTypeColumn.ItemsSource = Application.Current.FindResource("keyArrayPagerType") as Pair[];
            PagerStatusColumn.ItemsSource = Application.Current.FindResource("keyArrayItemStatus") as Pair[];
            PagerColorColumn.ItemsSource = Application.Current.FindResource("keyArrayColor") as Pair[];
            this.PagerGrid.ItemsSource = null;
            this.PagerGrid.ItemsSource = pagerDatatable.DefaultView;
            this.DataContext = null;
            this.DataContext = this;
        }

        private void txboxNumPrefix_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            Regex re = new Regex("[A-Za-z]");//[0-9A-Za-z]   //@"\S"
            e.Handled = !re.IsMatch(e.Text);
        }

        private void txboxRegion_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            Regex re = new Regex("[0-9A-Za-z]");//[0-9A-Za-z]   //@"\S"
            e.Handled = !re.IsMatch(e.Text);
        }

        private void cboNumFormat_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            pagerDatatable.Clear();
        }
    }


    public class Pair
    {
        public UInt32 Id { get; set; }
        public string Name { get; set; }

        public Pair(UInt32 Id, string Name)
        {
            this.Id = Id;
            this.Name = Name;
        }

        public Pair()
        {
            this.Id = 0;
            this.Name = "";
        }

        public override int GetHashCode()
        {
            return Name.GetHashCode() + (int)Id;
        }

        public override bool Equals(object obj)
        {
            if (obj == this)
                return true;
            if (!(obj is Pair))
                return false;

            var pair = (Pair)obj;

            return Name == pair.Name && Id == pair.Id;
        }
    }
    class CrcCheck
    {
        private static UInt16[] crc_table = new UInt16[]
        {
            0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
            0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
            0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
            0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
            0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
            0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
            0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
            0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
            0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
            0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
            0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
            0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
            0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
            0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
            0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
            0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
        };

        static public UInt16 crc16(byte[] buf, int len)
        {
            UInt16 crc = 0;
            byte crc_H8 = 0;
            foreach (var item in buf)
            {
                crc_H8 = (byte)(crc >> 8);
                crc <<= 8;
                crc ^= crc_table[crc_H8 ^ item];
                if (--len == 0)
                    break;
            }
            return crc;
        }
    }

    public class CommPort
    {
        private const int TRUE = 1;
        private const int FALSE = 0;

        ///<summary>
        ///端口名称(COM1,COM2...COM4...)
        ///</summary>
        public string Port = "COM1";
        ///<summary>
        ///波特率9600
        ///</summary>
        public int BaudRate = 9600;
        ///<summary>
        ///数据位4-8
        ///</summary>
        public byte ByteSize = 8; //4-8
        ///<summary>
        ///奇偶校验0-4=no,odd,even,mark,space
        ///</summary>
        public byte Parity = 0;   //0-4=no,odd,even,mark,space
        ///<summary>
        ///停止位
        ///</summary>
        public byte StopBits = 0;   //0,1,2 = 1, 1.5, 2
        ///<summary>
        ///超时长
        ///</summary>
        public int ReadTimeout = 100;
        ///<summary>
        ///串口是否已经打开
        ///</summary>
        public bool Opened = false;
        ///<summary>
        /// COM口句柄
        ///</summary>
        private HANDLE m_hComm = (HANDLE)User.INVALID_HANDLE_VALUE;


        ///<summary>
        /// 重叠事件句柄
        ///</summary>
        private HANDLE hEvent = (HANDLE)User.INVALID_HANDLE_VALUE;

        private Thread readThread;

        public delegate void DataReceivedDel(ref byte[] buf, int len);
        public event DataReceivedDel DataReceived;

        ///<summary>
        ///在后台线程里读取串口数据
        ///</summary>
        private void ReadDataHandle()
        {
            COMSTAT stat = new COMSTAT();
            OVERLAPPED ovlCommPort = new OVERLAPPED();
            int bytesRead = 0;
            int bytesInBuf = 0;
            int dwMask = 0;
            int dwErrorFlags = 0;
            bool b = false;
            HANDLE hComm = m_hComm;

            byte[] BufferRead = new byte[512];
            //IntPtr bufferRead = Marshal.AllocHGlobal(512);

            ovlCommPort.hEvent = (IntPtr)Kernel.CreateEvent(IntPtr.Zero, FALSE, FALSE, IntPtr.Zero);
            hEvent = ovlCommPort.hEvent;
            int err;
            byte[] testbuf = new byte[] { 0x06 };
            ClearReceiveBuf();
            while (Opened && hComm == m_hComm)
            {
                //DataReceived(ref testbuf/*BufferRead*/, /*bytesRead*/1);
                if (b)
                {
                    if ((dwMask & Kernel.EV_ERR) != 0)
                    {
                        Kernel.ClearCommError(hComm, ref dwErrorFlags, ref stat);
                    }
                    else if ((dwMask & Kernel.EV_RXCHAR) != 0)
                    {
                        Kernel.ClearCommError(hComm, ref dwErrorFlags, ref stat);
                        bytesInBuf = stat.cbInQue;
                        if (bytesInBuf > 0)
                        {
                            if (bytesInBuf > 512)
                            {
                                bytesInBuf = 512;
                            }
                            Array.Clear(BufferRead, 0, BufferRead.Length);
                            //unsafe
                            {
                                //fixed (byte* p = BufferRead)
                                lock (lockComm)
                                {
                                    //System.Diagnostics.Debug.Assert(p != null);
                                    b = (Kernel.ReadFile(hComm, BufferRead/*(IntPtr)p*/, bytesInBuf, ref bytesRead, ref ovlCommPort) != 0);//stat.cbInQue
                                    if (!b)
                                    {
                                        err = Kernel.GetLastError();
                                        if (err == ERROR.ERROR_IO_PENDING)
                                        {
                                            //若Internal=0时表明返回STATUS_SUCCESS，于是GetOverlappedResult返回TRUE，
                                            //即成功返回；InternalHigh的值保存在lpNumberOfBytesTransferred中。
                                            //若Internal!=0表示出现错误，于是GetOverlappedResult返回FALSE, GetLastError值就是Internal值。
                                            b = (Kernel.GetOverlappedResult(hComm, ref ovlCommPort, ref bytesRead, TRUE) > 0);
                                        }
                                        else
                                        {
                                            //System.Diagnostics.Trace.WriteLine("ReadFile NO IO_PENDING");
                                        }
                                    }
                                }
                            }

                            if (b && (bytesRead > 0))
                            {
                                if (DataReceived != null)
                                {
                                    try
                                    {
                                        //Marshal.Copy(bufferRead, BufferRead, 0, bytesRead);
                                        DataReceived(ref BufferRead, bytesRead);
                                        bytesRead = 0;
                                    }
                                    catch (Exception ex)
                                    {
                                        string s = ex.ToString();
                                        System.Diagnostics.Debug.Assert(false);
                                    }
                                }
                            }
                        }

                    }


                }
                //Kernel.ZeroMemory(bufferRead, 512);
                b = (Kernel.WaitCommEvent(hComm, ref dwMask, ref ovlCommPort) > 0);
                if (!b)
                {
                    err = Kernel.GetLastError();
                    if (err == ERROR.ERROR_IO_PENDING)
                    {
                        //若Internal=0时表明返回STATUS_SUCCESS，于是GetOverlappedResult返回TRUE，
                        //即成功返回；InternalHigh的值保存在lpNumberOfBytesTransferred中。
                        //若Internal!=0表示出现错误，于是GetOverlappedResult返回FALSE, GetLastError值就是Internal值。
                        b = (Kernel.GetOverlappedResult(hComm, ref ovlCommPort, ref bytesRead, TRUE) > 0);
                    }
                    else
                    {
                        //System.Diagnostics.Trace.WriteLine("WaitCommEvent NO IO_PENDING");
                    }
                }
            }
            //Marshal.FreeHGlobal(bufferRead);
            hEvent = (HANDLE)User.INVALID_HANDLE_VALUE;
            Kernel.CloseHandle(ovlCommPort.hEvent);
        }


        private OVERLAPPED ovlWrite = new OVERLAPPED();

        ///<summary>
        ///建立与串口的连接
        ///</summary>
        public int Open()
        {
            if (Opened) return 0;
            DCB dcb = new DCB();
            COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();

            // 打开串口
            m_hComm = (IntPtr)Kernel.CreateFile("\\\\.\\" + Port, Kernel.GENERIC_READ | Kernel.GENERIC_WRITE
                , 0, IntPtr.Zero, Kernel.OPEN_EXISTING, Kernel.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
            if (m_hComm == (HANDLE)User.INVALID_HANDLE_VALUE)
            {
                return -1;
            }
            if (Kernel.SetCommMask(m_hComm, Kernel.EV_ERR | Kernel.EV_RXCHAR) == 0)// Kernel.EV_ERR | Kernel.EV_TXEMPTY| 
            {
                Kernel.CloseHandle(m_hComm);
                m_hComm = (HANDLE)User.INVALID_HANDLE_VALUE;
                return -1;
            }

            // 设置输入、输出缓冲区的大小，清空输入输出缓冲区
            Kernel.SetupComm(m_hComm, 512, 512);
            Kernel.PurgeComm(m_hComm, Kernel.PURGE_TXCLEAR | Kernel.PURGE_RXCLEAR | Kernel.PURGE_RXABORT | Kernel.PURGE_TXABORT);

            // 设置通信超时时间
            Kernel.GetCommTimeouts(m_hComm, ref ctoCommPort);
            ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            Kernel.SetCommTimeouts(m_hComm, ref ctoCommPort);

            //设置串口参数
            Kernel.GetCommState(m_hComm, ref dcb);

            dcb.DCBlength = Marshal.SizeOf(dcb);
            dcb.BaudRate = BaudRate;
            dcb.ByteSize = (byte)ByteSize;
            dcb.StopBits = StopBits;
            dcb.Parity = (byte)Parity;

            //------------------------------
            //DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */
            //DWORD fParity: 1;     /* Enable parity checking          */
            //DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */
            //DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */
            //DWORD fDtrControl:2;  /* DTR Flow control                */
            //DWORD fDsrSensitivity:1; /* DSR Sensitivity              */
            //DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
            //DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */
            //DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */
            //DWORD fErrorChar: 1;  /* Enable Err Replacement          */
            //DWORD fNull: 1;       /* Enable Null stripping           */
            //DWORD fRtsControl:2;  /* Rts Flow control                */
            //DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
            //DWORD fDummy2:17;     /* Reserved                        */
            dcb.fBitFields &= ~((UInt32)0x02);
            dcb.fBitFields |= 0x1091;
            //--------------------------------
            //dcb.wReserved = 0;                       //没有使用，必须为0      
            dcb.XonLim = 512;                          //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数
            dcb.XoffLim = 512;                         //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数
            dcb.XonChar = 0x11;                         //发送和接收的XON字符
            dcb.XoffChar = 0x13;                        //发送和接收的XOFF字符
                                                        //dcb.ErrorChar = 0;                       //代替接收到奇偶校验错误的字符
                                                        //dcb.EofChar = 0;                         //用来表示数据的结束     
                                                        //dcb.EvtChar = 0;                         //事件字符，接收到此字符时，会产生一个事件       
                                                        //dcb.wReserved1 = 0;                      //没有使用

            if (0 == Kernel.SetCommState(m_hComm, ref dcb))
            {
                return -2;
            }

            Opened = true;
            //bufferWrite = Marshal.AllocHGlobal(512);
            ovlWrite.hEvent = (IntPtr)Kernel.CreateEvent(IntPtr.Zero, FALSE, FALSE, IntPtr.Zero);

            readThread = new Thread(ReadDataHandle);
            readThread.Start();
            return 0;
        }

        ///<summary>
        ///关闭串口,结束通讯
        ///</summary>
        public void Close()
        {
            if (m_hComm != (HANDLE)User.INVALID_HANDLE_VALUE)
            {
                Opened = false;
                if (hEvent != (HANDLE)User.INVALID_HANDLE_VALUE)
                {
                    Kernel.SetEvent(hEvent);
                }
                Kernel.SetEvent(m_hComm);
                Kernel.CloseHandle(m_hComm);
                Kernel.CloseHandle(ovlWrite.hEvent);
                //Marshal.FreeHGlobal(bufferWrite);
                //bufferWrite = IntPtr.Zero;
                m_hComm = (HANDLE)User.INVALID_HANDLE_VALUE;
                readThread.Join();
            }
        }

        //private byte[] BufferWrite = new byte[25];
        private readonly object lockComm = new object();
        //private IntPtr bufferWrite;
        ///<summary>
        ///向串口写数据
        ///</summary>
        ///<param name="WriteBytes">数据数组</param>
        public int Write(ref byte[] WriteBytes)
        {
            //一次发送不能大于25字节
            System.Diagnostics.Debug.Assert(WriteBytes != null && WriteBytes.Length <= 25);
            //System.Diagnostics.Debug.Assert(bufferWrite != IntPtr.Zero);
            if (m_hComm != (HANDLE)User.INVALID_HANDLE_VALUE)
            {
                int BytesWritten = 0;
                try
                {
                    //Array.Copy(WriteBytes, 0, BufferWrite, 0, WriteBytes.Length);

                    //unsafe
                    {
                        //fixed (byte* p = BufferWrite)
                        lock (lockComm)
                        {
                            //Marshal.Copy(WriteBytes, 0, bufferWrite, WriteBytes.Length);
                            do
                            {
                                if (0 != Kernel.WriteFile(m_hComm, WriteBytes/*(IntPtr)p*/, WriteBytes.Length, ref BytesWritten, ref ovlWrite))
                                {
                                    int err = Kernel.GetLastError();
                                    if (err == ERROR.ERROR_IO_PENDING)
                                    {
                                        if (0 != Kernel.GetOverlappedResult(m_hComm, ref ovlWrite, ref BytesWritten, TRUE))
                                        {
                                            BytesWritten = -1;
                                        }
                                        break;
                                    }
                                    else
                                    {
                                        System.Diagnostics.Trace.WriteLine("WriteFile NO IO_PENDING");
                                    }
                                    BytesWritten = -1;
                                    break;
                                }
                                else
                                {
                                    int err = Kernel.GetLastError();
                                    System.Diagnostics.Trace.WriteLine(string.Format("WriteFile Failed,Error:{0:D}", err));
                                }
                            } while (false);
                            //Kernel.ZeroMemory(bufferWrite, 512);
                        }
                    }


                    //Array.Clear(BufferWrite, 0, BufferWrite.Length);

                }
                catch (Exception ex)
                {
                    string s = ex.ToString();
                    System.Diagnostics.Debug.Assert(false);
                    return -1;
                }

                return BytesWritten;
            }
            else
            {
                return -1;
            }
        }

        ///<summary>
        ///清除接收缓冲区
        ///</summary>
        ///<returns></returns>
        public void ClearReceiveBuf()
        {
            if (m_hComm != (HANDLE)User.INVALID_HANDLE_VALUE)
            {
                Kernel.PurgeComm(m_hComm, Kernel.PURGE_RXABORT | Kernel.PURGE_RXCLEAR);
            }
        }

        ///<summary>
        ///清除发送缓冲区
        ///</summary>
        public void ClearSendBuf()
        {
            if (m_hComm != (HANDLE)User.INVALID_HANDLE_VALUE)
            {
                Kernel.PurgeComm(m_hComm, Kernel.PURGE_TXABORT | Kernel.PURGE_TXCLEAR);
            }
        }
    }


    //public class ColorConvertor : IValueConverter
    //{
    //    public static string[] Colors_CH = { "不显示", "红色", "绿色", "黄色" };
    //    public static string[] Colors_EN = { "None", "Red", "Green", "Yellow" };

    //    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        if(culture == culture_ch)
    //        {
    //            return Colors_CH[(UInt32)value];
    //        }
    //        else
    //        {
    //            return Colors_EN[(UInt32)value];
    //        }
    //    }

    //    //界面传向源
    //    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        if (culture == culture_ch)
    //        {
    //            return Array.IndexOf(Colors_CH, value);
    //        }
    //        else
    //        {
    //            return Array.IndexOf(Colors_EN, value);
    //        }
    //    }
    //};
}
